﻿// <copyright file="Level.cs" company="TenneySoftware">
// Copyright (c) 2009 All Right Reserved
// </copyright>
// <author>Robert Tenney</author>
// <email>rob10e@yahoo.com</email>
// <date>9/26/2009</date>
// <summary>The level.</summary>

// License:

// Product: Engine.csproj
// Author: Robert N. Tenney
// Copyright: 9/26/2009

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation version 2
// of the License.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

// This license covers all source code, binaries, and other materials related to this project
// unless specifically stated otherwise.

using System;
using System.Drawing;

namespace TenneySoftware.Engine {
    /// <summary>
    /// Class that holds and accesses the level.
    /// </summary>
    public class Level {
        /// <summary>
        /// The level.
        /// </summary>
        private TileData[][] level;

        /// <summary>
        /// The level's size.
        /// </summary>
        private Size size;

        /// <summary>
        /// The level's width.
        /// </summary>
        private int width;
        
        /// <summary>
        /// The level's height.
        /// </summary>
        private int height;
        
        /// <summary>
        /// The level's bounds.
        /// </summary>
        private Rectangle bounds;
        
        /// <summary>
        /// Initializes a new instance of the Level class.
        /// </summary>
        /// <param name="size">Size to set the level to.</param>
        public Level(Size size) {
            this.level = new TileData[size.Height][];
            this.size = size;
            this.width = size.Width;
            this.height = size.Height;
            this.bounds = new Rectangle(Point.Empty, size);
            for (int y = 0; y < size.Height; y++) {
                this.level[y] = new TileData[size.Width];
            }
        }

        /// <summary>
        /// Gets the size of the level.
        /// </summary>
        /// <value>
        /// The size of the level.</value>
        public Size Size {
            get {
                return this.size;
            }
        }

        /// <summary>
        /// Gets the width of the level.
        /// </summary>
        /// <value>
        /// The width of the level.
        /// </value>
        public int Width {
            get {
                return this.width;
            }
        }

        /// <summary>
        /// Gets the height of the level.
        /// </summary>
        /// <value>
        /// The height of the level.</value>
        public int Height {
            get {
                return this.height;
            }
        }

        /// <summary>
        /// Gets the bounds of the level.
        /// </summary>
        /// <value>
        /// The bounds of the level.
        /// </value>
        public Rectangle Bounds {
            get {
                return this.bounds;
            }
        }

        /// <summary>
        /// Checks to see if the location is within the bounds of the level.
        /// </summary>
        /// <param name="locationX">Location X.</param>
        /// <param name="locationY">Location Y.</param>
        /// <returns>True if location is within the bounds of the level.</returns>
        public bool IsLocationWithinBounds(int locationX, int locationY) {
            bool result = false;
            if (this.Bounds.Contains(locationX, locationY)) {
                result = true;
            }
            
            return result;
        }
        
        /// <summary>
        /// Checks to see if the location is within the bounds of the level.
        /// </summary>
        /// <param name="location">The location to check.</param>
        /// <returns>True if location is within the bounds of the level.</returns>
        public bool IsLocationWithinBounds(Point location) {
            return this.IsLocationWithinBounds(location.X, location.Y);
        }
        
        /// <summary>
        /// Sets the level's data at given location.
        /// </summary>
        /// <param name="locationX">Location X.</param>
        /// <param name="locationY">Location Y.</param>
        /// <param name="data">The TileData data to set.</param>
        public void SetLevel(int locationX, int locationY, TileData data) {
            if (this.Bounds.Contains(locationX, locationY)) {
                this.level[locationY][locationX] = data;
            } else {
                throw new LocationOutsideOfBoundsException("Location: " + new Point(locationX, locationY).ToString() +
                        " is outside of the level bounds (" + this.Bounds.ToString() +
                        ").");
            }
        }

        /// <summary>
        /// Sets the level's data at given location.
        /// </summary>
        /// <param name="location">The tile's location.</param>
        /// <param name="data">The TileData data to set.</param>
        public void SetLevel(Point location, TileData data) {
            this.SetLevel(location.X, location.Y, data);
        }

        /// <summary>
        /// Gets the level's data at given location.
        /// </summary>
        /// <param name="locationX">Location X.</param>
        /// <param name="locationY">Location Y.</param>
        /// <returns>The tile at the location.</returns>
        public TileData GetLevel(int locationX, int locationY) {
            if (this.Bounds.Contains(locationX, locationY)) {
                return this.level[locationY][locationX];
            } 
            
            return TileData.Null();
        }

        /// <summary>
        /// Gets the level's data at given location.
        /// </summary>
        /// <param name="location">The tile's location.</param>
        /// <returns>The tile at the location.</returns>
        public TileData GetLevel(Point location) {
            return this.GetLevel(location.X, location.Y);
        }
    }
}
